#include "diamondsq.h"
#include "num/rand.h"
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    
#include <string.h>

using namespace num;

DiamondSq::DiamondSq() :
	m_PointA(0),
	m_Width(0), m_Height(0),
	m_pRand(0),
	m_MaxRange(0),
	m_Bump(0)
{

}

DiamondSq::~DiamondSq()
{
	UTIL_SAFE_DELETEA(m_PointA);
}

void	DiamondSq::Init(int	Width, int Height, int	Range,  float	Bump)
{
	m_Bump  = Bump;
	// initialize
	m_Width = Width;
	m_Height = Height;
	m_MaxRange = Range;
	m_PointA = new float[m_Width * m_Height];
	memset(m_PointA, 0, sizeof(float) * m_Width * m_Height);
	m_pRand = &num::RAND32::Instance();
	// generate the four seeds
	SetValue(0, 0, m_pRand->RandFloat(0, (float)m_MaxRange));
	SetValue(m_Width-1, 0, m_pRand->RandFloat(0, (float)m_MaxRange));
	SetValue(0, m_Height-1, m_pRand->RandFloat(0, (float)m_MaxRange));
	SetValue(m_Width-1, m_Height-1, m_pRand->RandFloat(0, (float)m_MaxRange));

	UpdateDiamond(0, 0, m_Width-1, m_Height-1);
}

float	DiamondSq::GetValue(int x, int y)
{
	if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) return 0;

	//	x = x % m_Width;
//	y = y % m_Height;
	return m_PointA[x + (y*m_Width)];
}
void			DiamondSq::SetValue(int x, int y, float v)
{
	if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) return ;
//	x = x % m_Width;
//	y = y % m_Height;
	UTIL_CLAMP(v, 0, (float)m_MaxRange);
	m_PointA[x + (y*m_Width)] = (float )v;
}
void			DiamondSq::UpdateDiamond(int fx, int fy, int tx, int ty)
{
	// generate the diamond
	int	dx = fx +  ((tx-fx) / 2);
	int	dy = fy +  ((ty-fy) / 2);

	float		P1 = GetValue(fx, fy);
	float		P2 = GetValue(tx, fy);
	float		P3 = GetValue(fx, ty);
	float		P4 = GetValue(tx, ty);

	//vert
	float	r = m_Bump * ((tx-fx)+(ty-fy));
	SetValue(dx, fy, ((P1+P2) * 0.5f));
	SetValue(dx, ty, ((P3+P4) * 0.5f));
	//center
	SetValue(dx, dy, ((P1+P2+P3+P4) * 0.25f) + m_pRand->RandFloat(-r, r));
	//horiz
	SetValue(fx, dy, ((P1+P3) * 0.5f));
	SetValue(tx, dy, ((P2+P4) * 0.5f));
	
	// is it small enough?
	if (tx-fx <=2) return;

	// generate the 4 subrects
	UpdateDiamond(fx, fy, dx, dy);	//tl
	UpdateDiamond(dx, fy, tx, dy);	//tr
	UpdateDiamond(fx, dy, dx, ty);	//bl
	UpdateDiamond(dx, dy, tx, ty);	//br
}


